home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- .lfcond
- title "TRACE - Interrupt Tracer"
- subttl Introduction
- page
- comment \
-
- TRACE is an INT tracer. It traps INT's, traces the registers at the entry
- to the INT, executes the INT itself, and then traces the regs at exit from
- the INT. It also allows the user at the keyboard to see all of this traced
- information, either at the screen or on the printer.
-
- The INT's that are to be traced are specified in the source code (see config
- section below). Once defined, they may be enabled or disabled from the
- keyboard.
-
- <<< REBOOT AS SOON AS POSSIBLE AFTER INVOKING TRACE!!! >>>
-
- This is not foolproof or bugfree. We use it 'cause it's a terrific tool
- for deprotecting copy-protected software. You use it at your own risk.
- When you've gotten a printout of the trace activity that interests you,
- reboot your system. Don't say that we didn't warn you.
-
- Enjoy.
-
-
- Usage is: TRACE [size]
-
- where: size is the size of the trace table in K
- between 10 and 63, default is 30
-
-
- Known problems:
-
- Programs that use: INT 21h function E0
- INT 2Eh
-
-
-
- \
- page
- code segment para public 'code'
- assume cs:code,ds:code
- public trace_begin,trace_curr,trace_end,trace_bytes
- public ict_index,hndlr_index,prt_base
- public our_cs,test_cs,periscope
- public rec_sizes,interp,old_int_5,prtsc
-
- extrn selvideo:near,selprint:near,print:near,print_hex:near
- extrn print_word:near,print_wordb:near,crlf:near,print_line:near
- extrn table_print:near
- extrn print_edit:near,feed:near,key:near,zap_hits:near
- extrn prt_sc:near
-
- extrn do_traces:near,do_enable:near,disp_active:near,do_fcb:near
- extrn init:near
-
- extrn trace_table:byte
-
- org 0100h
- start: jmp init
-
- include b:trace1e.aic
-
-
- ; note that the number of ict's is set by number_icts in trace1e.aic
- ; and implicetly in code throughout this module.
-
- ; note that you need an ICT for some INT 21h AH = 0F0h for the
- ; detection of TRACE already being installed feature to work
- ; ICT with low ah = 0dh and high ah = ffh works fine.
-
- ; ict parms are:
- ; flags,flags2,int,low ah, high ah, saved cs:ip,
- ; count of entries,ict number
-
- ; ict flags are:
- ; f_active tracing on at start-up
- ; f_ret far ret with original flags, flags on stack
- ; f_ret2 far ret with updated flags, no flags on stack
- ; f_iret iret with original flags, no flags on stack
-
- ; ict flags2 are:
- ; f_call This call will return. Example INT 21H, in general
-
- ict0 ICT <F_ACTIVE+F_RET2+F_ENABLE,F_CALL,013H,0,0ffh,0,0,0>
- ;ROM BIOS INT 13h (all)
- ict1 ICT <F_ACTIVE+F_RET+F_ENABLE,0,020h,0,0ffh,0,0,1>
- ;DOS EXIT
- ict2 ICT <F_ACTIVE+F_RET2,F_CALL,021H,0,0ch,0,0,2>
- ;DOS funcs 00h thru 0Ch
- ict3 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,0dh,030h,0,0,3>
- ;DOS func 0Dh thru 030h
- ict4 ICT <F_ACTIVE+F_RET+F_ENABLE,0,021H,031h,031h,0,0,4>
- ;DOS func 031h TSR
- ict5 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,032h,04Bh,0,0,5>
- ;DOS funcs 032h thru 4Bh
- ict6 ICT <F_ACTIVE+F_RET2+F_ENABLE,0,021H,04Ch,04Ch,0,0,6>
- ;DOS func 04Ch EXIT
- ict7 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,04Dh,0ffh,0,0,7>
- ;DOS funcs 04Dh thru FFh
- ict8 ICT <F_ACTIVE+F_RET+F_ENABLE,F_CALL,025h,0,0ffh,0,0,8>
- ;RAW disk I/O
- ict9 ICT <F_ACTIVE+F_RET+F_ENABLE,F_CALL,026h,0,0ffh,0,0,9>
- ;RAW disk I/O
- ict10 ICT <F_ACTIVE+F_RET+F_ENABLE,0,027h,0,0ffh,0,0,10>
- ;DOS TSR
- ict11 ICT <F_ACTIVE+F_RET2+F_ENABLE,0,02Eh,0,0ffh,0,0,11>
- ;DOS undocumented .BAT call
-
- ict12 ICT <0,0,0,0,0,0,12> ;unused
- ict13 ICT <0,0,0,0,0,0,13> ;unused
- ict14 ICT <0,0,0,0,0,0,14> ;unused
- ict15 ICT <0,0,0,0,0,0,15> ;unused
-
-
- ;*******************************************************
- ; E N D C O N F I G U R A T I O N
- ;*******************************************************
-
- subttl Resident Storage
- page
-
- ;
- ; Things defined here are present even after we become resident and
- ; exit to DOS.
- ;
-
-
- ;********************************************************
- ;
- ; Index table pointing to all ICT's
- ;
- ;********************************************************
-
- ict_index label word
- dw offset ict0
- dw offset ict1
- dw offset ict2
- dw offset ict3
- dw offset ict4
- dw offset ict5
- dw offset ict6
- dw offset ict7
- dw offset ict8
- dw offset ict9
- dw offset ict10
- dw offset ict11
- dw offset ict12
- dw offset ict13
- dw offset ict14
- dw offset ict15
-
- ;********************************************************
- ;
- ; Index table pointing to all handlers
- ;
- ;********************************************************
-
- hndlr_index label word
- dw offset handler0
- dw offset handler1
- dw offset handler2
- dw offset handler3
- dw offset handler4
- dw offset handler5
- dw offset handler6
- dw offset handler7
- dw offset handler8
- dw offset handler9
- dw offset handler10
- dw offset handler11
- dw offset handler12
- dw offset handler13
- dw offset handler14
- dw offset handler15
-
- ;********************************************************
- ;
- ; Trace table pointers. Actual trace table slung over
- ; initialization code in TRACE12.ASM
- ;
- ;********************************************************
-
- trace_begin dw offset trace_table ;address of trace table begin
- trace_curr dw offset trace_table ;address of next entry
- trace_end dw offset trace_table ;address of end of trace table
- trace_bytes dw trace_size ;size of trace table in bytes
-
- ;********************************************************
- ;
- ; Table of sizes for each trace record type. Must be in same
- ; order as record types themselves.
- ;
- ;********************************************************
-
- rec_sizes label word
- dw size BEFORE
- dw size AFTER
- dw size FCB
- dw size ASCIIZ
-
- ;********************************************************
- ;
- ; Table of INT 21h functions that include an FCB pointer in DS:DX
- ;
- ;********************************************************
-
- FCB_table label byte
- db 0fh,10h,11h,12h,13h,14h,15h,16h,17h,21h,22h,23h,24h,27h,28h
- FCB_end label byte
-
-
- ;********************************************************
- ;
- ; Table of INT 21h functions that include an ASCIIZ pointer in DS:DX
- ;
- ;********************************************************
-
- ASCIIZ_table label byte
- db 4bh,3ch,3dh,41h,43h,4eh,56h,5ah,5bh,39h,3ah,3bh
- ASCIIZ_end label byte
-
- ;********************************************************
- ;
- ; Misc storage
- ;
- ;********************************************************
-
- old_int_5 dd ? ;address of previous Prt-Sc routine
- our_cs dw 0 ;our CS (not for segment checking)
- test_cs dw 0 ;our normalized CS (for segment checking)
- long_addr dd 0 ;for long JMP's and CALLs
- our_ICT dw 0 ;for quick save of our ICT pointer
- our_flags db 0 ;for quick save of our ICT flags
- prt_base dw 0 ;base I/O address of printer
- ;prt_flag db 0 ;non-zero to send output to printer
- db 255 dup (0) ;stack for Periscope Int handler
- our_tos dw 0 ;top of that stack
- stack_inuse db 0 ;non-zero when above stack is in use
- save_ss dw 0 ;for stack-swapping
- save_sp dw 0
-
-
- subttl Interrupt Trappers and Tracing
- page
-
- ;********************************************************
- ;
- ; Interrupt handler entry points for each ICT
- ;
- ;********************************************************
-
- handler macro ictloc
- cli ;*** NO INTERRUPTS!!! ***
- push bp ;save stack pointer, so that...
- mov bp,sp ;...we can ref things via BP
- push bx ;set BX to point to ICT
- mov bx,offset cs:ictloc
- jmp int_common ;goto common code
- endm
-
- interrupt proc far
-
- handler0:
- handler ict0
-
- handler1:
- handler ict1
-
- handler2:
- handler ict2
-
- handler3:
- handler ict3
-
- handler4:
- handler ict4
-
- handler5:
- handler ict5
-
- handler6:
- handler ict6
-
- handler7:
- handler ict7
-
- handler8:
- handler ict8
-
- handler9:
- handler ict9
-
- handler10:
- handler ict10
-
- handler11:
- handler ict11
-
- handler12:
- handler ict12
-
- handler13:
- handler ict13
-
- handler14:
- handler ict14
-
- handler15:
- handler ict15
-
- int_common:
-
- push ax
-
- ;********************************************************
- ;
- ; Common code for all trapped INT's.
- ;
- ; At this point:
- ;
- ; BX holds ICT address.
- ; BP points to stack as follows:
- ;
- ; AX
- ; BX
- ; (BP) ----> BP
- ; +2 IP of caller
- ; +4 CS of caller
- ; +6 FLAGS of caller
- ;
- ;********************************************************
-
- ; At this point we get the int number in AH. We invent an esoteric INT 21H
- ; value for telling the initialization code we are already here
-
- cmp cs:[bx].ICT_intnum,21h ;check interrupt # being traced
- jne notint21 ;if not 21h go on.
- mov ax,-4[bp] ;get original AX
- cmp ax,iamhere ;is it me ?
- jne notmyint ;no, go on
- mov word ptr -2[bp],iamhere ;set BX to flag
- notmyint:
- pop ax ;restore ah
- push ax ;restore stack
- notint21:
- test cs:[bx].ICT_flags,F_ENABLE ;tracing enabled for this ICT?
- jz no_trace ;no, don't trace it
- cmp ah,cs:[bx].ICT_AH_lo ;is AH within bounds?
- jb no_trace ;no, don't trace it
- cmp ah,cs:[bx].ICT_AH_hi
- ja no_trace ;no, don't trace it
-
- ;
- ; See if we should check caller's CS:IP
- ;
-
- test cs:[bx].ICT_flags,F_BELOW+F_ROM
- jz int_common3 ;no segment checks to be made
-
- mov ax,2[bp] ;get caller's IP
- shr ax,1 ;prepare to normalize segment #
- shr ax,1
- shr ax,1
- shr ax,1
- add ax,4[bp] ;add in segment
-
- ;
- ; ------ AX now equals normalized segment #
- ;
-
- test cs:[bx].ICT_flags,F_BELOW
-
- jz int_common2 ;don't check for invoker below us
- cmp ax,cs:test_cs ;is caller below us?
- jb no_trace ;yes, don't trace
-
- int_common2:
-
- test cs:[bx].ICT_flags,F_ROM
-
- jz int_common3 ;don't check for invoker in ROM
- cmp ax,0c000h ;is caller in ROM?
- jae no_trace ;yes, don't trace
-
- int_common3:
-
- ;
- ; See if we have room for this trace
- ;
-
- mov ax,cs:trace_curr ;get address of next entry
- push ax
- add ax,size BEFORE ;add size of this record
- ; cmp ax,offset cs:last_byte ;would record fit?
- cmp ax,cs:trace_end ;would record fit?
- pop ax
- jb yes_trace ;yes, there's room
-
- no_trace:
-
- ;
- ; We are not to trace this INT, for whatever reason.
- ; Just go to original handler, and return to caller (not to us).
- ;
-
- mov ax,word ptr cs:[bx].ICT_orig_hndlr
- mov word ptr cs:long_addr,ax
- mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
- mov word ptr cs:long_addr+2,ax
- pop ax
- pop bx
- pop bp
- jmp cs:long_addr ;let original handler return to caller
-
-
- yes_trace:
-
- ;
- ; We are to proceed with trace of this INT. Make trace entry.
- ;
-
- push es
- push di
-
- ;
- ; At this point:
- ;
- ; AX holds offset to next trace entry.
- ; BX holds ICT address.
- ; BP points to stack as follows:
- ;
- ; DI
- ; ES
- ; AX
- ; BX
- ; (BP) ----> BP
- ; +2 IP of caller
- ; +4 CS of caller
- ; +6 FLAGS of caller
- ;
-
- mov di,ax ;set ES:DI to next trace entry
- mov ax,cs
- mov es,ax
- cld ;forward!!!
- mov ah,cs:[bx].ICT_intnum ;get interrupt # being traced
- mov al,cs:[bx].ICT_num ;get ICT #, make BEFORE record type
- stosw
- mov ax,-4[bp] ;original AX
- stosw
- mov ax,-2[bp] ;original BX
- stosw
- mov ax,cx
- stosw
- mov ax,dx
- stosw
- mov ax,-6[bp] ;original ES
- stosw
- mov ax,ds
- stosw
- mov ax,ss
- stosw
- mov ax,bp ;original SP
- add ax,2
- stosw
- mov ax,si
- stosw
- mov ax,-8[bp] ;original DI
- stosw
- mov ax,[bp] ;original BP
- stosw
- mov ax,4[bp] ;caller's CS
- stosw
- mov ax,2[bp] ;caller's IP
- stosw
-
- mov cs:trace_curr,di ;save spot for next trace entry
- inc cs:[bx].ICT_hits ;bump number of traces made for this ICT
-
- ;
- ; We're done with the BEFORE trace. See if we are to do an FCB or ASCIIZ
- ; trace record.
- ;
-
- test cs:[bx].ICT_flags,F_FCB
- jz no_FCB ;no, we are definitely not supposed to
- cmp cs:[BX].ICT_intnum,021h ;is this an INT 21h?
- jnz no_FCB ;no, can't trace it then
-
- ;
- ; Search through ASCIIZ function table, to see if function that was called
- ; is one that contains an ASCIIZ pointer in DS:DX
- ;
-
- mov ax,-4[bp] ;get AX at time of call
- push cx
- mov di,offset cs:ASCIIZ_table
- mov cx,offset cs:ASCIIZ_end
- sub cx,di ;CX now has size of table
- mov al,ah ;get function to AL
- repnz scasb ;see if it's in table
- pop cx
- jz trace_ASCIIZ ;it's there, so do ASCIIZ trace
-
- ;
- ; Search through FCB function table, to see if function that was called
- ; is one that contains an FCB pointer in DS:DX
- ;
-
- push cx
- mov di,offset cs:FCB_table
- mov cx,offset cs:FCB_end
- sub cx,di ;CX now has size of table
- repnz scasb ;see if it's in table
- pop cx
- jnz no_FCB ;no FCB or ASCIIZ trace called for
-
- ;
- ; We are to do trace of FCB pointed to by DS:DX
- ;
-
- mov al,00100000b ;trace record number for FCB trace
- mov ah,size FCB ;size of record
- jmp short trace_common ;rest is common code
-
- trace_ASCIIZ:
-
- ;
- ; We are to do trace of ASCIIZ string pointed to by DS:DX
- ;
-
- mov al,00110000b ;trace record number for ASCIIZ trace
- mov ah,size ASCIIZ ;size of record
-
- trace_common:
-
- ;
- ; Copy bytes from DS:DX to new ASCIIZ or FCB trace record.
- ;
- ; At this point:
- ;
- ; AL holds trace record type, properly positioned in bits 7-4
- ; AH holds size of record that we're doing (the full record)
- ;
-
- sub ah,2 ;minus two bytes for record header
- mov di,cs:trace_curr ;see if there's room...
- push di
- push ax
- mov al,ah ;get record size to AX
- xor ah,ah
- add di,ax
- cmp di,cs:trace_end
- pop ax
- pop di
- jae no_FCB ;no room
- push ax ;save AX over this
- mov ah,cs:[bx].ICT_intnum ;start header with interrupt #
- or al,cs:[bx].ICT_num ;add ICT number to trace type
- stosw ;start new record with it
- pop ax ;restore AX
- push cx
- push si
- mov si,dx ;access DS:DX as DS:SI
- mov cl,ah ;record size to CX
- xor ch,ch
- rep movsb ;that's how many to copy
- pop si
- pop cx
- mov cs:trace_curr,di ;save offset to next record
-
- no_FCB: ;end of FCB/ASCIIZ tracing
-
- ;end of tracing, period
-
- test cs:[bx].ICT_flags2,F_CALL
- jnz call_old ;if marked for call then call far
-
- ;else: for ints that don't return like 20h and 27h then just jmp far
-
- mov ax,word ptr cs:[bx].ICT_orig_hndlr
- mov word ptr cs:long_addr,ax
- mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
- mov word ptr cs:long_addr+2,ax
-
- pop di
- pop es
- pop ax
- pop bx
- pop bp
- jmp cs:long_addr ;invoke original handler via jump
-
- call_old:
-
- ;
- ; Having traced all of those, now invoke original interrupt handler. Have
- ; it return to us, not the original caller of the interrupt.
- ;
-
- mov cs:our_ICT,bx ;save ICT pointer for a nanosecond
- mov al,cs:[bx].ICT_flags ;save copy of flags that we can get to
- mov cs:our_flags,al
-
- mov ax,word ptr cs:[bx].ICT_orig_hndlr
- mov word ptr cs:long_addr,ax
- mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
- mov word ptr cs:long_addr+2,ax
-
- pop di
- pop es
- pop ax
- pop bx
- pop bp
- push cs:our_ICT ;save ICT pointer on stack
- test cs:our_flags,F_RET ;should we push flags?
- jnz no_flags ;no, cause they'd be left on stack
- pushf ;yes, give handler some flags to drop
-
- no_flags:
- call cs:long_addr ;invoke original handler
-
-
- ;
- ; We're back from the real interrupt handler, and can make the "after" trace.
- ; Our ICT address is on stack.
- ;
-
- sti ;give world a crack at interrupts
- nop
- nop
- cli ;*** NO INTERRUPTS!!! ***
- push bp ;establish stack reference
- mov bp,sp
- pushf ;save resultant flags
- push es
- push di
- push ax
- push bx
-
- ;
- ; At this point:
- ;
- ; BX
- ; AX
- ; DI
- ; ES
- ; FLAGS (as returned by real interrupt)
- ; (BP) --------> BP
- ; ICT address
- ; IP of caller
- ; CS of caller
- ; FLAGS of original caller
- ;
-
- mov bx,2[bp] ;recover ICT address
- mov di,cs:trace_curr ;room for "after" trace entry?
- push di
- add di,size AFTER
- ; cmp di,offset cs:last_byte
- cmp di,cs:trace_end
- pop di
- jae no_after ;no, skip it
- mov ax,cs ;make ES:DI point to next entry
- mov es,ax
- cld ;forward!!!
- mov ah,cs:[bx].ICT_intnum ;get interrupt #
- mov al,cs:[bx].ICT_num ;get ICT #, make AFTER record type
- or al,00010000b
- stosw
- mov ax,-8[bp] ;AX at int's return
- stosw
- mov ax,-10[bp] ;BX at int's return
- stosw
- mov ax,cx
- stosw
- mov ax,dx
- stosw
- mov ax,-4[bp] ;ES at int's return
- stosw
- mov ax,ds
- stosw
- mov ax,si
- stosw
- mov ax,-6[bp] ;DI at int's return
- stosw
- mov ax,[bp] ;BP at int's return
- stosw
- mov ax,-2[bp] ;FLAGS at int's return
- stosw
-
- mov cs:trace_curr,di ;save offset to next entry
-
- no_after:
-
- ;
- ; All done making "after" trace, or we've skipped it cause there was
- ; no room for it.
- ;
- ; Now just exit back to the original caller.
- ;
-
- mov al,cs:[bx].ICT_flags ;save flags where we can get to them
- mov cs:our_flags,al
- pop bx
- pop ax
- pop di
- pop es
- popf
- pop bp
- pop cs:our_ICT ;drop ICT address without affecting flags
-
- ;
- ; HOW we exit is extremely important. We must exit the same way that the
- ; real interrupt does.
- ;
-
- pushf ;save current flags in case we return them
- test cs:our_flags,F_RET
- jnz exit_ret
- test cs:our_flags,F_RET2
- jnz exit_ret2
-
- ;
- ; Assume IRET.
- ;
-
- exit_iret:
- popf ;exit via IRET, reloading original flags
- STI ;Allow interrupts now
- iret
-
- exit_ret2:
- popf ;exit via RET 2, discarding original flags
- STI ;Allow interrupts now
- ret 2
-
- exit_ret:
- popf ;exit via far RET, leaving original flags
- STI ;Allow interrupts now
- ret
-
- interrupt endp
-
- page
- ;*********************************************
- ;
- ; Handle main menu selection whose ASCII keypress is in AL.
- ;
- ; Returns: CARRY SET if we should loop back to main menu.
- ; CARRY CLEAR to exit.
- ;
- ;*********************************************
-
- do_main proc near
- push ax
- cmp al,'P' ;select printer?
- jnz do_main1 ;no
- call selprint ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main1:
- cmp al,'S' ;select screen?
- jnz do_main2 ;no
- call selvideo ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main2:
- cmp al,'T' ;Dump Traces?
- jnz do_main3 ;no
- call do_traces ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main3:
- cmp al,'E' ;Enable ICT?
- jnz do_main4 ;no
- mov al,F_ENABLE ;yes, get bit value to set/clear
-
- do_main3b:
- call do_enable ;enable/disable F_ENABLE per AL
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main4:
- cmp al,'D' ;Disable ICT?
- jnz do_main5 ;no
- mov al,0 ;yes, get bit value to set/clear
- jmp do_main3b
-
- do_main5:
- cmp al,'L' ;List ICT's?
- jnz do_main6 ;no
- call disp_active ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main6:
- cmp al,'C' ;Clear trace table?
- jnz do_main7 ;no
- call zap_hits ;yes, do it
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main7:
- cmp al,'Q' ;Quit?
- jnz do_main7a ;no
- clc ;"Exit" flag
- jmp short do_main9
-
- do_main7a:
- cmp al,'W' ;PrtSc call?
- jnz do_main8 ;no
- call prt_sc
- clc ;"Exit" flag
- jmp short do_main9
-
- do_main8:
- cmp al,'F' ;F_FCB toggle?
- jnz do_main8B ;no
- call do_fcb ;yes, toggle something
- stc ;"Loop back to main menu" flag
- jmp short do_main9
-
- do_main8b:
-
- ; ------ Unknown selection
-
- stc ;"Loop back to main menu" flag
-
- do_main9:
- pop ax
- ret
- do_main endp
-
-
- subttl Interpretation - Misc Routines
- page
- ;********************************************************************
- ;* *
- ;* This file contains the routines that interpret selected *
- ;* BEFORE trace records and print out sensible summaries of *
- ;* their meanings. This sure beats having to read a lotta hex *
- ;* function codes. *
- ;* *
- ;* The main routine - interp() - is called just after we've *
- ;* printed all of the trace record in hex. If this record is *
- ;* one that we know about, we should now print a one-line *
- ;* interpretation of the record. This is done via lower-level *
- ;* routines called by interp() per the INT in the record. *
- ;* *
- ;********************************************************************
-
-
- ;********************************************************************
- ;
- ; Interpret BEFORE trace record at [SI].
- ;
- ;********************************************************************
-
- interp proc near
- push bx
- push ax
- mov ah,[SI].B_int ;get INT type
- mov bx,offset interp_tab ;point to table of handlers
-
- interp2:
- cmp ah,[bx] ;does this handler go with this INT?
- jnz interp5 ;no
- mov bx,1[bx] ;yes, get handler's address
- call bx ;call that handler
- jmp interp9 ;exit
-
- interp5:
- add bx,3 ;up to next entry in table
- cmp bx,offset interp_end ;searched whole table yet?
- jb interp2 ;no, try next one
-
- interp9:
-
- pop ax
- pop bx
- ret
- interp endp
-
- ;
- ; Table of interpreters for various interrupts.
- ;
- ; Each entry is as follows:
- ;
- ; db <intnum> ;interrupt number
- ; dw offset <handler> ;address of handler to interpret this int's record
- ;
- ;
-
- interp_tab label byte
- db 013h ;INT 13h is Diskette I/O
- dw offset interp_13 ;handler for INT 13h
- db 020h ;INT 20h is DOS Program exit
- dw offset interp_20 ;handler for INT 20h
- db 021h ;INT 21h is DOS Function Handler
- dw offset interp_21 ;handler for INT 21h
- db 025h ;INT 025H is DOS ABSOLUTE DISK READ
- dw offset interp_25
- db 026h ;INT 026H is DOS ABSOLUTE DISK WRITE
- dw offset interp_25 ;uses same interpreter
- db 027h ;INT 027H is DOS TSR
- dw offset interp_27 ;uses same interpreter
- db 02Eh ;INT 02EH is undoc DOS .BAT
- dw offset interp_2E ;uses same interpreter
- interp_end label byte ;end of table
-
- subttl Interpretation - INT 13 (Diskette I/O)
- page
- ;
- ; Tables used to interpret INT 13h in TRACE1E.AIC
- ;
-
- Floppy_or_Hard db 0,"Floppy:",0
- db 080h,"Fixed:",080h
-
- Cyl_or_Track db 0,"Track:",0
- db 080h,"Cyl:",080h
-
-
- int13_line label byte
- db cr,lf," "
- db Edit_Call
- int13_F_or_H db 0
- dw offset Floppy_or_Hard
- dw offset table_print
- db Edit_Dec8
- int13_drive db 0
- db " Head:"
- db Edit_Dec8
- int13_head db 0
- db " "
- db Edit_Call
- int13_C_or_T db 0
- dw offset Cyl_or_Track
- dw offset table_print
- db Edit_Dec16
- int13_cyl dw 0
- db " Sect:"
- db Edit_Dec8
- int13_sect db 0
- db " #Sects:"
- db Edit_Dec8
- int13_numsects db 0
- db " "
- db Edit_Call
- int13_func db 0
- dw offset int13_functab
- dw offset table_print
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 13h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_13 proc near
- push dx
- push cx
- push ax
- mov dx,[SI].B_dx ;get DX at time of INT
- mov al,dl ;Get drive #
- and al,080h ;isolate floppy/hard bit
- mov int13_F_or_H,al ;use it to select device name...
- mov int13_C_or_T,al ;...as well as cylinders/tracks
- and dl,07fh ;isolate drive #
- mov int13_drive,dl
- mov int13_head,dh ;store head #
- mov cx,[SI].B_cx ;get CX at time of INT
- xor ax,ax ;calc 10-bit cylinder #
- mov al,cl
- shl ax,1
- shl ax,1
- mov al,ch
- mov int13_cyl,ax ;save as word
- and cl,00111111b ;isolate sector #
- mov int13_sect,cl
- mov ax,[SI].B_ax ;get AX at time of INT
- mov int13_numsects,al
- mov int13_func,ah
- mov dx,offset int13_line ;now print edited line
- call print_edit
- pop ax
- pop cx
- pop dx
- ret
- interp_13 endp
-
- subttl Interpretation - INT 20h (DOS)
- page
-
- int20_line label byte
- db cr,lf," DOS: interrupt 20h - terminate program"
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 20h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_20 proc near
- push dx
- mov dx,offset int20_line
- call print_edit
- pop dx
- ret
- interp_20 endp
-
-
-
-
- subttl Interpretation - INT 21h (DOS)
- page
- ;
- ; Tables used in interpreting INT 21h
- ;
- include b:trace1.aic
-
-
-
- int21_line label byte
- db cr,lf," DOS: "
- db Edit_Call
- int21_func db 0
- dw offset int21_functab
- dw offset table_print
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 21h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_21 proc near
- push dx
- push ax
- mov ax,[SI].B_ax ;get AX at time of int
- mov byte ptr int21_func,ah ;use it to select function
- mov dx,offset int21_line
- call print_edit
- pop ax
- pop dx
- ret
- interp_21 endp
-
- subttl Interpretation - INT 25h and 26h (Absolute disk I/O)
- page
- ;
- ; Tables used to interpret INT's 25h and 26h
- ;
-
- int25_functab label byte
- db 025h,"Read",0
- db 026h,"Write",080h
-
- int25_line label byte
- db cr,lf," DOS Absolute "
- db Edit_Call
- int25_func db 0
- dw offset int25_functab
- dw offset table_print
- db " Drive:"
- db Edit_Dec8
- int25_drv db 0
- db " Sector:"
- db Edit_Dec16
- int25_sect dw 0
- db " #Sectors:"
- db Edit_Dec16
- int25_numsects dw 0
- db " Buf "
- db Edit_Word
- int25_seg dw 0
- db ":"
- db Edit_Word
- int25_off dw 0
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 25h or INT 26h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_25 proc near
- push dx
- push ax
- mov al,[SI].B_int ;get INT that was done (25h or 26h)
- mov int25_func,al ;move to printline
- mov ax,[SI].B_ax ;get drive # from AL
- mov int25_drv,al ;move to printline
- mov ax,[SI].B_dx ;get starting sector # from DX
- mov int25_sect,ax ;move to printline
- mov ax,[SI].B_cx ;get # sectors from CX
- mov int25_numsects,ax ;move to printline
- mov ax,[SI].B_ds ;get buffer segment from DS
- mov int25_seg,ax ;move to printline
- mov ax,[SI].B_bx ;get buffer offset from BX
- mov int25_off,ax ;move to printline
- mov dx,offset int25_line ;now print edited line
- call print_edit
- pop ax
- pop dx
- ret
- interp_25 endp
-
- int27_line label byte
- db cr,lf," DOS: interrupt 27h - TSR"
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 27h BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_27 proc near
- push dx
- mov dx,offset int27_line
- call print_edit
- pop dx
- ret
- interp_27 endp
-
- int2E_line label byte
- db cr,lf," DOS: interrupt 2Eh - Undocumented .BAT service"
- db Edit_End
-
- ;**************************************************
- ;
- ; Interpret INT 2Eh BEFORE trace record at [SI]
- ;
- ;**************************************************
-
- interp_2E proc near
- push dx
- mov dx,offset int2E_line
- call print_edit
- pop dx
- ret
- interp_2E endp
-
-
-
- subttl Periscope Interrupt Interface
- page
-
- ;*****************************************
- ;
- ; This is the interrupt handler use by Periscope to access this code.
- ; It may also be called by SHIFT-PrtSc.
- ;
- ; On entry, AH contains function:
- ;
- ; 1 - 8: User Breakpoint checks (BU 1 thru BU 8, then GT)
- ; 9 - FFh: User exits (/U 9 thru /U FFh)
- ; 0FFh: Called by PrtSc
- ;
- ;*****************************************
-
- db "PS" ;sentinel that Periscope checks for
- periscope proc far
-
- ;
- ; First, make very sure that we aren't being re-entered!!! This would
- ; wipe out our stack which is already in use.
- ;
-
- cli
- test cs:stack_inuse,0ffh
- jz periscope2 ;it's ok
-
- periscope1:
-
- mov al,0ffh ;tell Periscope "No Break, No Command to be executed"
- iret ;busy, call back later
-
- periscope2:
-
- ;
- ; If we've been entered via Periscope User Break function (during single-stepping,
- ; with BU 1 thru BU 8 in effect), then exit immediately. Things are slow
- ; enough without us being executed when we have no Breakpoint checking to do.
- ;
-
- cmp ah,9 ;BU 1 thru BU 8?
- jb periscope1 ;yes, exit
-
-
- ;
- ; On entry to this periscope int, we ought to save everything but AX,
- ; and switch to our own stack. Periscope itself doesn't require this,
- ; but the PrtSc routine assumes it.
- ;
-
- mov cs:stack_inuse,0ffh ;mark our stack busy
- mov cs:save_ss,ss
- mov cs:save_sp,sp
- mov ss,cs:our_cs
- mov sp,offset our_tos
- push cs:save_ss ;save old stack stuff for later
- push cs:save_sp
- push bx
- push cx
- push dx
- push si
- push di
- push es
- push ds
- push bp
- mov ds,cs:our_cs ;set DS to us for assume ds:code
- sti
-
- ;
- ; Give user stats about trace buffer size
- ;
- mov ax,trace_bytes
- mov word ptr size_trace,ax
- ; mov ax,offset last_byte ;get # free bytes
- mov ax,trace_end ;get # free bytes
- sub ax,trace_curr
- mov word ptr size_freeb,ax
- mov dx,offset size_msg
- call print_edit
-
- periscope_menu:
-
- ;
- ; Now display menu and get his selection, until we are to exit
- ;
-
- mov dx,offset mainmenu
- call print_line ;put up main menu
- call feed ;extra CRLF's for printer
- call key ;get keypress
- call do_main ;process it
- jc periscope_menu ;we are to loop back
- mov dx,offset shadows ;give him exit message
- call print_line
-
-
- periscope_exit:
-
- ;
- ; Restore regs and original stack. AX is already set to return result.
- ;
-
- cli
- pop bp
- pop ds
- pop es
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop cs:save_sp ;restore original stack
- pop cs:save_ss
- mov ss,cs:save_ss
- mov sp,cs:save_sp
- mov cs:stack_inuse,0 ;mark our stack not busy
- iret
- periscope endp
-
- mainmenu db cr,lf
- db " TRACE Commands:",cr,lf
- db " Output to: Trace Trace Sel List ICT "
- db " Trace Cmd PrtSc",cr,lf
- db "(P)rt (S)crn (E)nable (D)isable (F)CB (T)race (L)ist "
- db "(C)lear (Q)uit (W)rite",cr,lf,"$"
-
- shadows db cr,lf
- db "Back to DOS"
- db cr,lf,"$"
-
- size_msg label byte
- db cr,lf
- db "TraceBuf Bytes:"
- db Edit_Dec16
- size_trace dw 0
- db " Free Bytes:"
- db Edit_Dec16
- size_freeb dw 0
- db Edit_End
-
- subttl INT 05 (SHIFT-PrtSc) Handler
- page
- ;**************************************************
- ;
- ; This is another way (besides Periscope) to talk to the tracer, and
- ; get it to report what it's found. This is not as clean a way as
- ; via Periscope, but it beats nothing if the Periscope board isn't in
- ; the system.
- ;
- ; This routine just calls the Periscope interrupt handler.
- ;
- ;**************************************************
-
- if prt_scr
-
- PrtSc proc far
- cli
- push es
- push ax
- mov ax,050h ;set ES to 0050:0000
- mov es,ax ;(the print-screen control byte)
- cmp byte ptr es:[0],1 ;are we busy with previous request?
- jz PrtSc_exit ;yes, don't do anything
- mov byte ptr es:[0],1 ;no, mark us busy now
- mov ah,0ffh ;call Periscope INT with special arg
- int peri_int
- mov byte ptr es:[0],0 ;mark us not busy now
-
- PrtSc_exit:
- pop ax
- pop es
- iret
- Prtsc endp
-
- endif
-
- code ends
- end start
-
-